package bakenote.ui;

import bakenote.data.RecipeSQLiteDB;
import bakenote.data.RecipeList;
import bakenote.core.Recipe;
import bakenote.core.RecipeGroup;
import org.apache.pivot.beans.BXML;
import org.apache.pivot.beans.BeanAdapter;
import org.apache.pivot.beans.Bindable;
import org.apache.pivot.collections.*;
import org.apache.pivot.util.Resources;
import org.apache.pivot.wtk.Component;
import org.apache.pivot.wtk.*;
import org.apache.pivot.wtk.Point;
import org.apache.pivot.wtk.content.TableViewTextAreaCellRenderer;

import java.awt.Font;
import java.net.URL;
import java.util.Comparator;

/**
 * @author lello
 */
public class RecipeTablePane extends TablePane implements Bindable {

    @BXML
    private TextInput searchBox = null;
    @BXML
    private TableView recipeTableView = null;
    // This is the list actually used for displaying items
    //private List<Recipe> foundItems = new ArrayList<Recipe>(RecipeList.getList());
    //private Recipe dragRecipe = null;
    private List<Recipe> dragRecipeList = new ArrayList<Recipe>();
    private static RecipeGroup recipeGroup = null;

    public RecipeTablePane() {
        // No-op
    }


    private MenuHandler recipeTableMenuHandler = new MenuHandler.Adapter() {

        @Override
        public boolean configureContextMenu(Component cmpnt, Menu menu, int x, int y) {

            int rowIndex = recipeTableView.getRowAt(y);
            final Recipe recipe = (Recipe) recipeTableView.getTableData().get(rowIndex);

            // Create the context menu
            Menu.Section menuSection1 = new Menu.Section();
            Menu.Item removeFromGroupMenuItem = new Menu.Item("Remove from group");
            menuSection1.add(removeFromGroupMenuItem);
            menu.getSections().add(menuSection1);

            if (recipeGroup != null) {
                removeFromGroupMenuItem.setEnabled(true);
                removeFromGroupMenuItem.setAction(new Action() {
                    @Override
                    public void perform(Component source) {
                        if (recipeGroup != null) {
                            //recipeGroup.remove(recipe);
                            try {
                                // update the currently selected group
                                recipeGroup.remove(recipe);
                                // update the recipes in the tableView
                                RecipeList.filter(null, recipeGroup);
                                // update the group members
                                RecipeSQLiteDB.updateGroupMembers(recipeGroup);
                            } catch (Exception e) {
                                System.out.println("Cannot find group...probably the database is compromised");
                            }
                        } else {
                            System.out.println("null group...");
                        }
                    }
                });
            } else {
                removeFromGroupMenuItem.setEnabled(false);
            }
            return false;
        }
    };

    public void setGroup(RecipeGroup rg) {
        recipeGroup = rg;
        RecipeList.filter(null,rg);
    }

    public TableView getRecipeTableView() {
        return recipeTableView;
    }

    // This listener update the list data
    private TextInputContentListener textInputTextListener = new TextInputContentListener.Adapter() {
        @Override
        public void textChanged(TextInput ti) {
            RecipeList.filter(ti.getText().toLowerCase(), recipeGroup);
        }
    };

    public void updateFilter() {
        RecipeList.filter(searchBox.getText().toLowerCase(), recipeGroup);
    }

    @Override
    public void setEnabled(boolean bool) {
        searchBox.setEnabled(bool);
        recipeTableView.setEnabled(bool);
    }

    public void initialize(Map<String, Object> map, URL url, Resources rsrcs) {
        // populate the TableView with the recipe list
        recipeTableView.setTableData(RecipeList.getList());
        recipeTableView.getTableViewSortListeners().add(tvsl);
        recipeTableView.setMenuHandler(recipeTableMenuHandler);
        // add the listener to the searchBox
        searchBox.getTextInputContentListeners().add(textInputTextListener);
        recipeTableView.setDragSource(dragSource);
        recipeTableView.setSort("name", SortDirection.ASCENDING);
    }

    private TableViewSortListener tvsl = new TableViewSortListener.Adapter() {

        @Override
        public void sortChanged(TableView tv) {
            Comparator comp = new RecipeTableViewRowComparator(tv);
            tv.getTableData().setComparator(comp);
        }
    };

    private DragSource dragSource = new DragSource() {

        @Override
        public boolean beginDrag(Component component, int x, int y) {
            TableView tableView = (TableView) component;
            int row = tableView.getRowAt(y);
            //dragRecipe = ((Recipe)tableView.getTableData().get(row));
            Sequence<Span> selectedRanges = tableView.getSelectedRanges();
            dragRecipeList.clear();
            for (int i = 0; i < selectedRanges.getLength(); i++) {
                Span selectedRange = selectedRanges.get(i);
                for (int j = selectedRange.start; j <= selectedRange.end; j++) {
                    Recipe r = (Recipe) tableView.getTableData().get(j);
                    dragRecipeList.add(r);
                }
            }
            return true;
        }

        @Override
        public void endDrag(Component component, DropAction dropAction) {
            //System.out.println("end drag");
        }

        @Override
        public boolean isNative() {
            return false;
        }

        @Override
        public LocalManifest getContent() {
            LocalManifest content = new LocalManifest();
            content.putText("recipe");
            content.putValue("recipe", dragRecipeList);
            return content;
        }

        @Override
        public Visual getRepresentation() {
            return null;
        }

        @Override
        public Point getOffset() {
            return null;
        }

        @Override
        public int getSupportedDropActions() {
            return DropAction.MOVE.getMask();

        }
    };

    private class RecipeTableViewRowComparator implements Comparator<Object> {

        private TableView tableView;

        public RecipeTableViewRowComparator(TableView tableView) {
            if (tableView == null) {
                throw new IllegalArgumentException();
            }
            this.tableView = tableView;
        }

        public int compare(Object o1, Object o2) {

            int result;

            TableView.SortDictionary sort = tableView.getSort();

            if (sort.getLength() > 0) {
                Dictionary<String, ?> row1;
                if (o1 instanceof Dictionary<?, ?>) {
                    row1 = (Dictionary<String, ?>) o1;
                } else {
                    row1 = new BeanAdapter(o1);
                }

                Dictionary<String, ?> row2;
                if (o2 instanceof Dictionary<?, ?>) {
                    row2 = (Dictionary<String, ?>) o2;
                } else {
                    row2 = new BeanAdapter(o2);
                }

                result = 0;

                int n = sort.getLength();
                int i = 0;

                while (i < n
                        && result == 0) {
                    Dictionary.Pair<String, SortDirection> pair = sort.get(i);

                    String columnName = pair.key;
                    SortDirection sortDirection = sort.get(columnName);

                    Object value1 = row1.get(columnName);
                    Object value2 = row2.get(columnName);

                    if (value1 == null
                            && value2 == null) {
                        result = 0;
                    } else if (value1 == null) {
                        result = -1;
                    } else if (value2 == null) {
                        result = 1;
                    } else {
                        String s1 = value1.toString();
                        String s2 = value2.toString();
                        result = s1.compareToIgnoreCase(s2);
                    }

                    result *= (sortDirection == SortDirection.ASCENDING ? 1 : -1);

                    i++;
                }
            } else {
                result = 0;
            }

            return result;
        }
    }

    public static class AuthorCellRenderer extends TableViewTextAreaCellRenderer {

        public AuthorCellRenderer() {
            this.getStyles().put("margin", 4);
        }

        @Override
        public void render(Object row, int rowIndex, int columnIndex,
                           TableView tableView, String columnName,
                           boolean selected, boolean highlighted, boolean disabled) {

            // First we render as a TextArea, then we change style
            super.render(row, rowIndex, columnIndex, tableView, columnName,
                    selected, highlighted, disabled);

            // Here we apply our custom styles
            if (row != null) {
                Recipe r = (Recipe) row;
                String name = r.getAuthor();
                if (name != null) {
                    getStyles().put("font", new Font("Verdana", Font.ITALIC, 12));
                }
            }
        }
    }

    /**
     public static class RatingCellRenderer extends TableViewImageCellRenderer {

     public RatingCellRenderer() {}

     @Override public void render(Object row, int rowIndex, int columnIndex,
     TableView tableView, String columnName,
     boolean selected, boolean highlighted, boolean disabled) {

     // Here we apply our custom styles
     if (row != null) {
     Recipe r = (Recipe) row;
     int rate = r.getRating();
     try {
     BufferedImage bimg = ImageIO.read(getClass().getResource("components/icons" + File.separator + "rate3.png"));
     Image img = new Picture(bimg);
     this.setImage(img);
     } catch (IOException ex) {
     Logger.getLogger(RecipeTablePane.class.getName()).log(Level.SEVERE, null, ex);
     }
     }
     }

     }  **/

}
